﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using ODP.Model;
using ODP.Enum;
using System.Web;

namespace ODP.Com
{
    public abstract class OAuthBase
    {
        private string m_customKey ;

        public string customKey
        {
            get { return m_customKey; }
            set { m_customKey = value; }
        }

        private string m_customSecret ;

        public string customSecret
        {
            get { return m_customSecret; }
            set { m_customSecret = value; }
        }

        public string tokenKey { get; set; }

        public string tokenSecret { get; set; }

        public string verify { get; set; }

        public string callbackUrl = "";

        public Encoding Charset { get; set; }

        public TwitterType twitterType { get; set; }

        public string baseurl { get; set; }

        protected string oauth_Signature { get; set; }

        public IList<APIInfo> apiInfoList { get; set;}

        private string m_format = "json";

        private string request_token_url;

        public string Request_token_url
        {
            get { return request_token_url; }
            set { request_token_url = value; }
        }

        private string access_token_url;

        public string Access_token_url
        {
            get { return access_token_url; }
            set { access_token_url = value; }
        }

        public string format
        {
            get { return m_format; }
            set { m_format = value; }
        }

        private string uid;

        public string Uid
        {
            get { return uid; }
            set { uid = value; }
        }

        

        #region 常量
        protected const string OAuthVersion = "1.0";
        protected const string OAuthParameterPrefix = "oauth_";
        protected const string OAuthConsumerKeyKey = "oauth_consumer_key";
        protected const string OAuthCallbackKey = "oauth_callback";
        protected const string OAuthVersionKey = "oauth_version";
        protected const string OAuthSignatureMethodKey = "oauth_signature_method";
        protected const string OAuthSignatureKey = "oauth_signature";
        protected const string OAuthTimestampKey = "oauth_timestamp";
        protected const string OAuthNonceKey = "oauth_nonce";
        protected const string OAuthTokenKey = "oauth_token";
        protected const string OAuthFormat = "format";
        protected const string oAauthVerifier = "oauth_verifier";
        protected const string OAuthTokenSecretKey = "oauth_token_secret";
        protected const string HMACSHA1SignatureType = "HMAC-SHA1";
        protected const string PlainTextSignatureType = "PLAINTEXT";
        protected const string RSASHA1SignatureType = "RSA-SHA1";
        protected string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        #endregion

        protected Random random = new Random();

        #region 计算哈希值
        /// <summary>
        /// 计算哈希值
        /// </summary>
        /// <param name="hashAlgorithm"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private string ComputeHash(HashAlgorithm hashAlgorithm, string data)
        {
            if (hashAlgorithm == null)
            {
                throw new ArgumentNullException("hashAlgorithm");
            }

            if (string.IsNullOrEmpty(data))
            {
                throw new ArgumentNullException("data");
            }

            byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(data);
            byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);

            return Convert.ToBase64String(hashBytes);
        }
        #endregion

        #region 初始化相关的身份认证参数
        /// <summary>
        /// 初始化相关的身份认证参数
        /// </summary>
        /// <param name="parameters"></param>
        private void AddParameter(ref List<QueryStringParameter> parameters, bool isformat = false)
        {
           

            if (this.twitterType == TwitterType.QQ)
            {
                parameters.Add(new QueryStringParameter(OAuthVersionKey, OAuthVersion));
                parameters.Add(new QueryStringParameter(OAuthNonceKey, GenerateNonce()));
                parameters.Add(new QueryStringParameter(OAuthTimestampKey, GenerateTimeStamp()));
                parameters.Add(new QueryStringParameter(OAuthSignatureMethodKey, HMACSHA1SignatureType));
                parameters.Add(new QueryStringParameter(OAuthConsumerKeyKey, customKey));

                if (isformat)
                {
                    parameters.Add(new QueryStringParameter(OAuthFormat, format));
                }

                if (!string.IsNullOrEmpty(tokenKey))
                {
                    parameters.Add(new QueryStringParameter(OAuthTokenKey, tokenKey));
                }
                else
                {
                    if (!string.IsNullOrEmpty(callbackUrl))
                    {
                        parameters.Add(new QueryStringParameter(OAuthCallbackKey, callbackUrl));
                    }
                }

                if (!string.IsNullOrEmpty(verify))
                {
                    parameters.Add(new QueryStringParameter(oAauthVerifier, verify));
                }
            }
            else
            {
                

                if (!string.IsNullOrEmpty(callbackUrl) && string.IsNullOrEmpty(tokenKey))
                {
                    parameters.Add(new QueryStringParameter("redirect_uri", callbackUrl));
                }


                if (!string.IsNullOrEmpty(tokenKey))
                {
                    parameters.Add(new QueryStringParameter("access_token", tokenKey));
                    //parameters.Add(new QueryStringParameter("source", customKey));

                }
                else
                {
                    if (!string.IsNullOrEmpty(verify))
                    {
                        parameters.Add(new QueryStringParameter("code", verify));
                    }

                    parameters.Add(new QueryStringParameter("client_id", customKey));

                }
            }

            
        }
        #endregion

        #region 生成一个时间戳
        /// <summary>
        /// 生成一个时间戳        
        /// </summary>
        /// <returns></returns>
        private string GenerateTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
        #endregion

        #region 获取一个随机数,用来防止url请求重复
        /// <summary>
        /// 获取一个随机数,用来防止url请求重复
        /// </summary>
        /// <returns></returns>
        private string GenerateNonce()
        {
            return random.Next(123400, 9999999).ToString();
        }
        #endregion

        #region 生成身份验证的url
        /// <summary>
        /// 生成身份验证的url
        /// </summary>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <param name="customKey"></param>
        /// <param name="customSecrect"></param>
        /// <param name="tokenKey"></param>
        /// <param name="tokenSecrect"></param>
        /// <param name="verify"></param>
        /// <param name="callbackUrl"></param>
        /// <param name="parameters"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        public void GetOauthUrl(string url, string httpMethod, string customKey, 
            string customSecrect, string tokenKey, string tokenSecrect, string verify,
            string callbackUrl, List<QueryStringParameter> parameters, out string queryString, out string request_Url)
        {
            //添加相关的参数到集合中
            AddParameter(ref parameters);
            parameters.Sort(new ParameterComparer());
            
            request_Url = GetUrlMain(new Uri(url));
            queryString = EncodeParameters(parameters);

            //获取拼凑完整的querystring字符串
            StringBuilder signatureBase = new StringBuilder();
            signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
            signatureBase.AppendFormat("{0}&", UrlEncode(request_Url));
            signatureBase.AppendFormat("{0}", UrlEncode(queryString));

            //计算签名字符串
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode(customSecret), string.IsNullOrEmpty(tokenSecret) ? "" : UrlEncode(tokenSecret)));

            oauth_Signature = ComputeHash(hmacsha1, signatureBase.ToString());

            queryString += "&oauth_signature=" + UrlEncode(oauth_Signature);
        }

        public void GetOauthUrl(string url, string httpMethod, List<QueryStringParameter> parameters, out string queryString, out string request_Url)
        {
            //添加相关的参数到集合中
            AddParameter(ref parameters);
            parameters.Sort(new ParameterComparer());
            request_Url = GetUrlMain(new Uri(url));
            queryString = EncodeParameters(parameters);
        }
        #endregion

        #region 请求信息的url
        /// <summary>
        /// 请求信息的url
        /// </summary>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <param name="customKey"></param>
        /// <param name="customSecrect"></param>
        /// <param name="tokenKey"></param>
        /// <param name="tokenSecrect"></param>
        /// <param name="verify"></param>
        /// <param name="callbackUrl"></param>
        /// <param name="parameters"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        public void GetRequestUrl(ref string queryString,string url, string httpMethod, string customKey,
            string customSecrect, string tokenKey, string tokenSecrect, string verify,
            string callbackUrl, List<QueryStringParameter> parameters)
        {
            //添加相关的参数到集合中
            AddParameter(ref parameters,true);

            parameters.Sort(new ParameterComparer());

            queryString = EncodeParameters(parameters);

            //获取拼凑完整的querystring字符串
            StringBuilder signatureBase = new StringBuilder();
            signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
            signatureBase.AppendFormat("{0}&", UrlEncode(url));
            signatureBase.AppendFormat("{0}", UrlEncode(queryString));

            //计算签名字符串
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode(customSecret), string.IsNullOrEmpty(tokenSecret) ? "" : UrlEncode(tokenSecret)));

            oauth_Signature = ComputeHash(hmacsha1, signatureBase.ToString());

            queryString += "&oauth_signature=" + UrlEncode(oauth_Signature);
        }
        #endregion

        #region 请求信息的url
        /// <summary>
        /// 请求信息的url
        /// </summary>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <param name="customKey"></param>
        /// <param name="customSecrect"></param>
        /// <param name="tokenKey"></param>
        /// <param name="tokenSecrect"></param>
        /// <param name="verify"></param>
        /// <param name="callbackUrl"></param>
        /// <param name="parameters"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        public void GetRequestUrl(ref string queryString, string url, string httpMethod, List<QueryStringParameter> parameters)
        {
            //添加相关的参数到集合中
            AddParameter(ref parameters, true);

            parameters.Sort(new ParameterComparer());

            queryString = EncodeParameters(parameters);

        }
        #endregion

        #region 获取请求的主地址
        /// <summary>
        /// 获取请求的主地址
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public string GetUrlMain(Uri url)
        {
            string normalizedUrl = null;
            normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host);
            if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))
            {
                normalizedUrl += ":" + url.Port;
            }
            normalizedUrl += url.AbsolutePath;

            return normalizedUrl;
        }
        #endregion

        #region 加密字符串
        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private string EncodeParameters(List<QueryStringParameter> parameters)
        {
            List<QueryStringParameter> encodeParams = new List<QueryStringParameter>();
            foreach (QueryStringParameter a in parameters)
            {
                encodeParams.Add(new QueryStringParameter(a.Name, UrlEncode(a.Value)));
            }

            return CastQueryStringParameterListToURLQueryString(encodeParams);
        }

        public string UrlEncode(string value)
        {
            var result = new StringBuilder();

            foreach (char symbol in value)
            {
                if (unreservedChars.IndexOf(symbol) != -1)
                {
                    result.Append(symbol);
                }
                else
                {
                    //some symbols produce > 2 char values so the system urlencoder must be used to get the correct data
                    if (String.Format("{0:X2}", (int)symbol).Length > 3)
                    {
                        // ReSharper disable PossibleNullReferenceException
                        result.Append(HttpUtility.UrlEncode(value.Substring(value.IndexOf(symbol), 1)).ToUpper());
                        // ReSharper restore PossibleNullReferenceException
                    }
                    else
                    {
                        result.Append('%' + String.Format("{0:X2}", (int)symbol));
                    }
                }
            }
            return result.ToString();
        }
        #endregion

        #region 将参数集合转换为url的querystring字符串
        /// <summary>
        /// 将参数集合转换为url的querystring字符串
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private string CastQueryStringParameterListToURLQueryString(List<QueryStringParameter> parameters)
        {
            StringBuilder result = new StringBuilder();

            foreach (QueryStringParameter qsp in parameters)
            {
                if (result.Length > 0)
                {
                    result.AppendFormat("&{0}={1}", qsp.Name, qsp.Value);
                }
                else
                {
                    result.AppendFormat("{0}={1}", qsp.Name, qsp.Value);
                }
            }

            return result.ToString();
        }
        #endregion

        #region 获取授权口令
        /// <summary>
        /// 获取授权口令
        /// </summary>
        /// <param name="customKey"></param>
        /// <param name="customSecret"></param>
        /// <returns></returns>
        public bool GetRequestToken()
        {
            
            List<QueryStringParameter> parameters = new List<QueryStringParameter>();
            string requestString = "";
            string request_Url = "";

            GetOauthUrl(Request_token_url, HttpMethod.GET.ToString(), customKey, customSecret, tokenKey, tokenKey, verify, callbackUrl, parameters, out requestString, out request_Url);

            return ParseToken(new SyncHttp().HttpGet(request_Url, requestString));
        }

        /// <summary>
        /// 获取授权口令
        /// </summary>
        /// <param name="customKey"></param>
        /// <param name="customSecret"></param>
        /// <returns></returns>
        public bool GetAccessToken()
        {
            bool result = true;

            

            string requestString = "";
            string request_Url = "";

            List<QueryStringParameter> parameters = new List<QueryStringParameter>();

            GetOauthUrl(Access_token_url, HttpMethod.GET.ToString(), customKey, customSecret, tokenKey, tokenKey, verify, callbackUrl, parameters, out requestString, out request_Url);

            result= ParseToken(new SyncHttp().HttpGet(request_Url, requestString));

            return result;
        }

        /// <summary>
        /// 拆分授权口令
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private bool ParseToken(string response)
        {
            if (string.IsNullOrEmpty(response))
            {
                return false;
            }

            string[] tokenArray = response.Split('&');

            if (tokenArray.Length < 2)
            {
                return false;
            }

            string strTokenKey = tokenArray[0];
            string strTokenSecrect = tokenArray[1];

            string[] token1 = strTokenKey.Split('=');
            if (token1.Length < 2)
            {
                return false;
            }
            tokenKey = token1[1];

            string[] token2 = strTokenSecrect.Split('=');
            if (token2.Length < 2)
            {
                return false;
            }
            tokenSecret = token2[1];

            return true;
        }
        #endregion
    }
}
